const Vue = require('vue')
const express = require('express')
// const { response } = require("express");
const fs = require('fs')
const { createBundleRenderer } = require('vue-server-renderer')
const setupDevServer = require('./build/setup-dev-server')

// const renderer = require("vue-server-renderer").createRenderer({
//   template: fs.readFileSync("./index.template.html", "utf-8"),
// });

//把上面的createRenderer 换成  createBundleRenderer
//接收的第一个参数是serverBundle ,指的是打包生成的vue-ssr-server-bundle.json
//第二个参数是一个选项对象
/* const serverBundle = require('./dist/vue-ssr-server-bundle.json')
const template = fs.readFileSync('./index.template.html', 'utf-8')
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
const renderer = require('vue-server-renderer').createBundleRenderer(
  serverBundle,
  {
    //模板
    template,
    //打包过后的生成的客服端资源构建清单
    clientManifest,
  }
) */

const server = express()

//在server 上挂载一个处理静态资源的中间件
//第一个参数是请求前缀，是一个具体的路径
//第二个参数 express.static 是中间件，尝试在 dist目录中查找资源，处理返回
server.use('/dist', express.static('./dist'))

const isProd = process.env.NODE_ENV === 'production'

let renderer
let onReady //接收开发模式 重新生成的 renderer 渲染器
if (isProd) {
  // 生产模式
  const serverBundle = require('./dist/vue-ssr-server-bundle.json')
  const template = fs.readFileSync('./index.template.html', 'utf-8')
  const clientManifest = require('./dist/vue-ssr-client-manifest.json')
  renderer = createBundleRenderer(serverBundle, {
    //模板
    template,
    //打包过后的生成的客服端资源构建清单
    clientManifest,
  })
} else {
  // 开发模式 -> 监视打包构建 -> 重新生成 Renderer 渲染器
  // 第一个参数是server 实例本身 const server = express()，因为需要的开发模式下给实例挂载中间件
  // 第二个参数是一个回调函数，会监视打包构建完成以后就会执行这个回调函数,这个回调函数需要传入 模板，打包过后的客服端和服务端文件
  onReady = setupDevServer(server, (serverBundle, template, clientManifest) => {
    // 根据打包的结果重新生成 renderer
    renderer = createBundleRenderer(serverBundle, {
      //模板
      template,
      //打包过后的生成的客服端资源构建清单
      clientManifest,
    })
  })
}

const render = async (req, res) => {
  try {
    //第一个参数就是上面定义的vue实例
    //第二个参数是的外部数据，是一个对象
    const html = await renderer.renderToString(
      //去除，不用我们创建，render会自动找到文件创建
      // app,
      {
        title: 'SSR学习',
        meta: `<meta name="description" content="SSR学习">`,
        url: req.url,
      }
    )
    //处理乱码，也可以在下面html里面加上完整的meta
    res.setHeader('Content-Type', 'text/html ; charset=utf8')
    //正确发送结果
    res.end(html)
  } catch (err) {
    res.status(500).end('Internal Server Error')
  }
}

// 生产模式下直接调用 render , 开发模式等待有了 Renderer 渲染器以后，调用 render 进行渲染
// 服务端路由设置为 * , 意味着所有的路由都会进入这里
server.get(
  '*',
  isProd
    ? render
    : async (req, res) => {
        // 等待有了 Renderer 渲染器以后，调用 render 进行渲染
        // 等待 onReady 渲染成功 调用 render()
        await onReady
        render(req, res)
      }
)

//开启3000端口
server.listen(3000, () => {
  console.log('server running at port 3000')
})
